package com.winit.schedule.task.tracker.monitor;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.winit.schedule.core.conf.Configuration;
import com.winit.schedule.core.model.AssignedTask;
import com.winit.schedule.core.model.TaskID;
import com.winit.schedule.core.service.AbstractService;
import com.winit.schedule.core.utils.Clock;
import com.winit.schedule.task.tracker.TaskTracker;
import com.winit.schedule.task.tracker.runner.AbstractTaskManager;
import com.winit.schedule.task.tracker.runner.StrategyTask;

/**
 * 监控超时任务
 * 
 * @author jianke.zhang 2015-3-12 下午6:42:35
 * @since 1.0
 */
public class ExpireTaskRunnerMonitor extends AbstractService {

    private static transient final Logger  logger         = LoggerFactory.getLogger(ExpireTaskRunnerMonitor.class);

    // 用来定时检查任务是否到期
    private final ScheduledExecutorService expireExecutor = Executors.newScheduledThreadPool(1);

    private TaskTracker                    taskTracker;

    public ExpireTaskRunnerMonitor(TaskTracker taskTracker){
        super("ExpireTaskRunnerMonitor");
        this.taskTracker = taskTracker;
    }

    @Override
    protected void serviceInit(Configuration conf) throws Exception {
        super.serviceInit(conf);
    }

    @Override
    protected void serviceStart() throws Exception {
        super.serviceStart();
        expireExecutor.scheduleWithFixedDelay(new ExpireThread(this), 3000, 3000, TimeUnit.MILLISECONDS);
    }

    @Override
    protected void serviceStop() throws Exception {
        super.serviceStop();
        expireExecutor.shutdown();
    }

    public void checkExpireTask() throws Exception {
        Map<TaskID, List<StrategyTask>> managerMap = taskTracker.getManagerMap();

        if (managerMap != null && !managerMap.isEmpty()) {
            TaskID[] keys = managerMap.keySet().toArray(new TaskID[] {});

            for (TaskID taskId : keys) {
                List<StrategyTask> taskManagers = managerMap.get(taskId);
                StrategyTask[] taskMgrs = taskManagers.toArray(new StrategyTask[] {});
                if (null != taskMgrs) {
                    for (StrategyTask taskMgr : taskMgrs) {
                        AssignedTask task = ((AbstractTaskManager) taskMgr).getTask();
                        if (task.getPermitRunEndTime() > 0) {
                            Date permitRunEndDate = Clock.getDate(task.getPermitRunEndTime());
                            Date currentDate = Clock.getCurrentDate();
                            if (permitRunEndDate.before(currentDate)) {
                                if (!taskMgr.isStop()) {
                                    if (logger.isDebugEnabled()) {
                                        logger.debug("Task reached the end of time, stop task:" + taskId);
                                    }
                                    ((AbstractTaskManager) taskMgr).completeSchedule(true);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    class ExpireThread implements Runnable {

        ExpireTaskRunnerMonitor expireMonitor;

        public ExpireThread(ExpireTaskRunnerMonitor expireMonitor){
            this.expireMonitor = expireMonitor;
        }

        @Override
        public void run() {
            try {
                Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
//                if (logger.isDebugEnabled()) {
//                    logger.debug("Check task expire.");
//                }

                expireMonitor.checkExpireTask();

            } catch (Exception ex) {
                logger.error("Check task expire fialure.", ex);
            }
        }

    }

}
